<style lang="less">
.code-editor{
    border: 1px solid #C0CCDA;
    border-radius: 4px;
    width: 100%;
    height: 200px;
    min-height: 200px;
}
</style>
<template>
<div class="code-editor" :style="{
    height: css(height),
    width: css(width)
}"></div>
</template>
<script>
import $ from 'jquery';
import Promise from 'bluebird';

const BASE_URL = '//cdn.bootcss.com/ace/1.2.9/';

const loadScript = function(name) {
    let caches = loadScript.caches;
    if(!caches) {
        caches = loadScript.caches = {};
    }

    let url = BASE_URL + name;
    if(url.slice(-3) !== '.js') {
        url += '.js';
    }

    if(!caches[url]) {
        $.ajaxSetup({ cache: true });

        caches[url] = new Promise((resolve, reject) => {
            $.getScript(url, resolve, reject);
        });
    }

    return caches[url];
};

export default {
    props: {
        value: String,
        width: [Number, String],
        height: [Number, String],
        theme: {
            type: String,
            default: 'chrome'
        },
        lang: {
            type: String,
            default: 'text'
        },
        options: {
            type: Object,
            default: () => {
                return {
                    // autoScrollEditorIntoView: true,
                    enableEmmet: true,
                    fontSize: 14
                };
            }
        }
    },
    data() {
        return {
            content: this.value
        };
    },
    methods: {
        css(inp) {
            if(/\d+$/.test(inp)) {
                return inp + 'px';
            }

            return inp;
        },
        init() {
            return this.loadAce()
            .then(ace => {
                let editor = ace.edit(this.$el);

                // shim
                editor.$blockScrolling = Infinity;

                // cache
                this._editor = editor;

                return editor;
            })
            .tap(() => {
                const {theme, lang} = this;

                return Promise.all([
                    loadScript('ext-emmet'),
                    loadScript('mode-' + lang),
                    loadScript('theme-' + theme)
                ]);
            })
            .tap(editor => {
                const {theme, lang, options} = this;

                Object.keys(options).forEach(k => {
                    editor.setOption(k, options[k]);
                });

                editor.getSession().setMode('ace/mode/' + lang);
                editor.setTheme('ace/theme/' + theme);
            })
            .tap(editor => {
                editor.setValue(this.value, 1);

                editor.on('change', () => {
                    this.content = editor.getValue();
                });
            })
            .catch(err => {
                throw err;
            });
        },
        loadAce() {
            return loadScript('ace')
            .then(() => {
                return window.ace;
            });
        },
        setContent(val) {
            if(val === this.content) {
                return;
            }

            this.content = val;

            if(this._editor) {
                this._editor.setValue(val, 1);
            }
        }
    },
    watch: {
        value(val) {
            this.setContent(val);
        },
        content(val) {
            this.$emit('input', val);
            this.$emit('change', val);
        }
    },
    created() {
        this.$nextTick(this.init);
    }
};
</script>
